package com.yang.booking.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yang.booking.dao.*;
import com.yang.booking.pojo.*;
import com.yang.booking.utils.GetDaysUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

@Service
public class AppointmentService {

    @Autowired
    private AppointmentMapper appointmentMapper;

    @Autowired
    private AppointmentRuleMapper appointmentRuleMapper;

    @Autowired
    private StoreMapper storeMapper;

//    @Autowired
//    private ShiftManagementService shiftManagementService;
//
//    @Autowired
//    private StoreMapper storeMapper;
//
//    @Autowired
//    private BiweeklyMapper biweeklyMapper;
//
//    @Autowired
//    private ShiftManagementMapper shiftManagementMapper;

    @Autowired
    private GetDaysUtils getDaysUtils;

    @Autowired
    private StaffService staffService;

    @Autowired
    private StaffMapper staffMapper;

    @Autowired
    private ShiftManagementService shiftManagementService;

    @Autowired
    private StaffRestMapper staffRestMapper;

    private final ReentrantLock reentrantLock = new ReentrantLock();

    @Transactional
    public Map<String, Object> insertAppointment(String storeId, int type, int userType, String userId, String userName, int source, int appType,
                                                 String beauticianId, String beauticianName, String arrivalDate,
                                                 String phone, String itemId, String itemName, String consumTime,
                                                 String roomId, String roomName, String serviceStartTime, String serviceEndTime,
                                                 String remarks, String temporaryArrangeId, String id, String iu) throws ParseException {

//        //计算服务结束时间
//        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
//        Date start = simpleDateFormat.parse(serviceStartTime);
//        Date end;
//        int afferenttEnd = Integer.parseInt(consumTime);
//        long correctEnd = 0;
//        if (afferenttEnd % 60 == 0 || afferenttEnd % 60 == 30){
//            end = new Date(start.getTime() + (long)(afferenttEnd*60*1000));
//        }else {
//            if (afferenttEnd % 60 < 30){
//                correctEnd = (long) ((afferenttEnd / 60 + 0.5) * 60);
//            }
//            if (afferenttEnd % 60 > 30){
//                correctEnd = (long)((afferenttEnd / 60 + 1) * 60);
//            }
//            end = new Date(start.getTime() + correctEnd*60*1000);
//        }
//
//        //方式一
//        List<String> stringList = shiftManagementService.queryStaffShift(storeId, beauticianId, arrivalDate, "2", "2");
//        boolean inside = false;
//        for (String s:stringList
//             ) {
//            if (serviceEndTime == s){
//                inside = true;
//                break;
//            }
//        }
//        if (inside){
//            QueryWrapper<Appointment> awrapper = new QueryWrapper<>();
//            awrapper.eq("beautician_id", beauticianId);
//            awrapper.eq("arrivalDate", arrivalDate);
//            List<Appointment> appointmentList = appointmentMapper.selectList(awrapper);
//            for (Appointment appointment : appointmentList
//            ) {
//                if (end.getTime() > simpleDateFormat.parse(appointment.getServiceStartTime()).getTime() &&
//                        end.getTime() <= simpleDateFormat.parse(appointment.getServiceEndTime()).getTime()) {
//                    Map<String, Object> msg = new HashMap<String, Object>();
//                    msg.put("massage", "服务时间有冲突");
//                    msg.put("code", 400);
//                    return msg;
//                }
//            }
//        }else {
//            Map<String, Object> msg = new HashMap<String, Object>();
//            msg.put("massage", "不在服务时间内");
//            msg.put("code", 400);
//            return msg;
//        }
//
//        //方式二
//        Store store = storeMapper.selectById(storeId);
//        QueryWrapper<Biweekly> wrapper = new QueryWrapper<>();
//        SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd");
//        String[] weeks = {"周日","周一","周二","周三","周四","周五","周六"};
//        Calendar calendar = Calendar.getInstance();
//        calendar.setTime(simpleDateFormat.parse(arrivalDate));
//        int week_index = calendar.get(Calendar.DAY_OF_WEEK) - 1;
//        if(week_index<0){
//            week_index = 0;
//        }
//        if (store.getSchedulingCycle() == 2) {
//            int week = calendar.get(Calendar.WEEK_OF_YEAR);
//            if (week % 2 == 0) {
//                wrapper.eq("name", "双" + weeks[week_index]);
//            } else {
//                wrapper.eq("name", "单" + weeks[week_index]);
//            }
//        }else {
//            wrapper.eq("name", weeks[week_index]);
//        }
//        Biweekly biweekly = biweeklyMapper.selectOne(wrapper);
//        ShiftManagement staffShift = shiftManagementMapper.queryStaffBiweeklyShift(beauticianId, biweekly.getId());
//        boolean inside = false;
//        for (String shiftTime:staffShift.getShiftTimeList().split(", ")
//        ) {
//            if (end.getTime() > simpleDateFormat1.parse(shiftTime.split(" - ")[0]).getTime() &&
//                    end.getTime() <= simpleDateFormat1.parse(shiftTime.split(" - ")[1]).getTime()) {
//                inside = true;
//                break;
//            }
//        }
//        if(inside) {
//            QueryWrapper<Appointment> awrapper = new QueryWrapper<>();
//            awrapper.eq("beautician_id", beauticianId);
//            awrapper.eq("arrivalDate", arrivalDate);
//            List<Appointment> appointmentList = appointmentMapper.selectList(awrapper);
//            for (Appointment appointment : appointmentList
//            ) {
//                if (end.getTime() > simpleDateFormat.parse(appointment.getServiceStartTime()).getTime() &&
//                        end.getTime() <= simpleDateFormat.parse(appointment.getServiceEndTime()).getTime()) {
//                    Map<String, Object> msg = new HashMap<String, Object>();
//                    msg.put("massage", "服务时间有冲突");
//                    msg.put("code", 400);
//                    return msg;
//                }
//            }
//        }else {
//            Map<String, Object> msg = new HashMap<String, Object>();
//            msg.put("massage", "不在服务时间内");
//            msg.put("code", 400);
//            return msg;
//        }

        //方式三

        QueryWrapper<Store> ewrapper = new QueryWrapper<>();
        ewrapper.eq("id",storeId);
        Store store = storeMapper.selectOne(ewrapper);

        QueryWrapper<AppointmentRule> wrapper = new QueryWrapper<>();
        wrapper.eq("store_id",storeId);
        AppointmentRule appointmentRule = appointmentRuleMapper.selectOne(wrapper);

        SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("HH:mm");
        Date start1 = simpleDateFormat1.parse(serviceStartTime);
        Date end1 = simpleDateFormat1.parse(serviceEndTime);
        List<String> staffShiftTimeList = new ArrayList<>();
        staffShiftTimeList.add(serviceStartTime);
        long i = 1;
        for (; ; ) {
            if (start1.getTime() + i * 30 * 60 * 1000 >= end1.getTime()) {
                break;
            }
            staffShiftTimeList.add(simpleDateFormat1.format(new Date(start1.getTime() + i * 30 * 60 * 1000)));
            i++;
        }

        QueryWrapper<Staff> swrapper = new QueryWrapper<>();
        swrapper.eq("store_id", storeId);
        swrapper.eq("app_situation", 1);
        swrapper.eq("position", "美容师");
        List<Staff> staffList = staffMapper.selectList(swrapper);

        reentrantLock.lock();

        for (String shiftTime : staffShiftTimeList
             ) {
            QueryWrapper<Appointment> awrapper1 = new QueryWrapper<>();
            awrapper1.eq("store_id", storeId);
            awrapper1.ne("type", 3);
            awrapper1.le("complete_service_start_time", arrivalDate + " " + shiftTime + ":00");
            awrapper1.gt("complete_service_end_time", arrivalDate + " " + shiftTime + ":00");
            awrapper1.ne("state", 3);
            int acount = appointmentMapper.selectCount(awrapper1);

            int rcount = 0;
            int ecount = 0;
            for (Staff staff : staffList
            ) {
                boolean tem = true;
                for (String staffShiftTime : shiftManagementService.queryStaffShift(storeId, staff.getId(), arrivalDate, "2", "1")
                ) {
                    if (staffShiftTime.equals(shiftTime)) {
                        tem = false;
                        break;
                    }
                }
                if (tem) {
                    rcount += 1;
                }

                QueryWrapper<StaffRest> rwrapper = new QueryWrapper<>();
                rwrapper.eq("staff_id", staff.getId());
                rwrapper.eq("rest_date", arrivalDate);
                rwrapper.eq("rest_time", shiftTime);
                if (staffRestMapper.selectOne(rwrapper) != null) {
                    ecount += 1;
                }
            }

            if (appointmentRule != null && appointmentRule.getMostMeanwhile() != 0) {
                if (appointmentRule.getMostMeanwhile() <= acount + rcount + ecount) {

                    reentrantLock.unlock();

                    Map<String, Object> msg = new HashMap<String, Object>();
                    msg.put("massage", "该店铺该时间段预约已满");
                    msg.put("code", 400);
                    return msg;
                }
            } else {
                if (staffList.size() <= acount + rcount + ecount) {

                    reentrantLock.unlock();

                    Map<String, Object> msg = new HashMap<String, Object>();
                    msg.put("massage", "该时间段预约已满");
                    msg.put("code", 400);
                    return msg;
                }
            }
        }

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date start = simpleDateFormat.parse(arrivalDate+" "+serviceStartTime+":00");
        Date end = simpleDateFormat.parse(arrivalDate+" "+serviceEndTime+":00");

        QueryWrapper<Appointment> awrapper = new QueryWrapper<>();
        awrapper.eq("beautician_id", beauticianId);
        awrapper.gt("complete_service_start_time", start);
        awrapper.lt("complete_service_end_time", end);
        awrapper.eq("type", 1);
        if (appointmentMapper.selectList(awrapper).size() > 0){

            reentrantLock.unlock();

            Map<String, Object> msg = new HashMap<String, Object>();
            msg.put("massage", "预约时间有冲突");
            msg.put("code", 400);
            return msg;
        }

        reentrantLock.unlock();

        if(source == 2 && appointmentRule != null){
            if((start.getTime() - new Date().getTime())/60/60/1000 < appointmentRule.getLatestReserve()){
                Map<String, Object> msg = new HashMap<String, Object>();
                msg.put("massage", "需要提前"+appointmentRule.getLatestReserve()+"小时预约");
                msg.put("code", 400);
                return msg;
            }
        }

        Appointment a = new Appointment();
        a.setRegionId(store.getRegionId());
        a.setStoreId(storeId);
        a.setType(type);
        a.setUserType(userType);
        a.setUserId(userId);
        a.setUserName(userName);
        a.setSource(source);
        a.setAppType(appType);
        a.setBeauticianId(beauticianId);
        a.setBeauticianName(beauticianName);
        a.setArrivalDate(arrivalDate);
        a.setPhone(phone);
        a.setItemId(itemId);
        a.setItemName(itemName);
        a.setConsumTime(consumTime);
        a.setRoomId(roomId);
        a.setRoomName(roomName);
        a.setServiceStartTime(serviceStartTime);
        a.setServiceEndTime(serviceEndTime);
        a.setRemarks(remarks);
        a.setState(1);
        a.setCompleteServiceStartTime(start);
        a.setCompleteServiceEndTime(end);
        a.setCreateAt(new Date());
        a.setUpdateAt(new Date());

        if(type == 3){
            a.setTemporaryArrangeId(temporaryArrangeId);
        }

        if(iu == "0") {
            appointmentMapper.insert(a);
        }else if(iu == "1"){
            a.setId(id);
            appointmentMapper.updateById(a);
        }

        appointmentMapper.insert(a);
        Map<String, Object> msg = new HashMap<String, Object>();
        msg.put("massage", "插入成功");
        msg.put("code", 200);
        return msg;
    }

    public Map<String, Object> queryAppointmentAll(String storeId, String serviceStartTime, String serviceEndTime, String userNameOrPhone,
                                                    String source, String appType, String state,
                                                    String beauticianId, String pageSize, String pageNo){

        QueryWrapper<Appointment> wrapper = new QueryWrapper<>();

        if (!serviceStartTime.equals("")){
            wrapper.ge("complete_service_start_time", serviceStartTime);
        }

        if (!serviceEndTime.equals("")){
            wrapper.le("complete_service_end_time", serviceEndTime);
        }

        if (!userNameOrPhone.equals("")){
            wrapper.likeRight("user_name", userNameOrPhone).or().like("user_name", userNameOrPhone).or().likeLeft("user_name", userNameOrPhone).or().
                    likeRight("phone", userNameOrPhone).or().likeLeft("phone", userNameOrPhone).or().like("phone",userNameOrPhone);

        }

        if (!source.equals("")){
            wrapper.eq("source", source);
        }

        if (!appType.equals("")){
            wrapper.eq("app_type", appType);
        }

        if (!state.equals("")){
            wrapper.eq("state", state);
        }

        if (!beauticianId.equals("")){
            wrapper.eq("beautician_id", beauticianId);
        }

        wrapper.eq("store_id",storeId);
        Page<Appointment> page = new Page<>(Long.parseLong(pageNo),Long.parseLong(pageSize));
        appointmentMapper.selectPage(page, wrapper);
        List<Appointment> appointmentList = page.getRecords();

        Map<String, Object> msg = new HashMap<String, Object>();
        msg.put("massage", "查询成功");
        msg.put("code", 200);
        Map<String, Object> data = new HashMap<String, Object>();
        msg.put("data", data);
        data.put("rows", appointmentList);
        data.put("total", appointmentList.size());

        return msg;
    }

    public Map<String, Object> cancleAppointment(String storeId, String appointmentId){

        QueryWrapper<AppointmentRule> wrapper = new QueryWrapper<>();
        wrapper.eq("store_id",storeId);
        AppointmentRule appointmentRule = appointmentRuleMapper.selectOne(wrapper);

        Appointment appointment = appointmentMapper.selectById(appointmentId);

        if((appointment.getCompleteServiceStartTime().getTime() - new Date().getTime())/60/60/1000 < appointmentRule.getLatestCancel()){
            Map<String, Object> msg = new HashMap<String, Object>();
            msg.put("massage", "需要提前"+appointmentRule.getLatestReserve()+"小时取消");
            msg.put("code", 400);
            return msg;
        }

        appointment.setState(3);
        appointmentMapper.updateById(appointment);

        Map<String, Object> msg = new HashMap<String, Object>();
        msg.put("massage", "取消成功");
        msg.put("code", 200);

        return msg;
    }

    public Map<String, Object> queryUserAppointment(String userId,String state, String pageSize, String pageNo){

        QueryWrapper<Appointment> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId);
        wrapper.in("state", state.split(","));
        Page<Appointment> page = new Page<>(Long.parseLong(pageNo),Long.parseLong(pageSize));
        appointmentMapper.selectPage(page, wrapper);
        List<Appointment> appointmentList = page.getRecords();

        Map<String, Object> msg = new HashMap<String, Object>();
        msg.put("massage", "查询成功");
        msg.put("code", 200);
        Map<String, Object> data = new HashMap<String, Object>();
        msg.put("data", data);
        data.put("rows", appointmentList);
        data.put("total", appointmentList.size());

        return msg;
    }

    public Map<String, Object> appointmentStatistics(String storeId,String regionId, String startTime, String endTime) throws ParseException {

        List<Map<String, Object>> dailyStatisticsList = new ArrayList<>();
        for (String day:getDaysUtils.getDays(startTime, endTime)
             ) {

            QueryWrapper<Appointment> wrapper = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper1 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper2 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper3 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper4 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper5 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper6 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper7 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper8 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper9 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper10 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper11 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper12 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper13 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper14 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper15 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper16 = new QueryWrapper<>();
            QueryWrapper<Appointment> wrapper17 = new QueryWrapper<>();

            if (!storeId.equals("")){
                wrapper.eq("store_id", storeId);
                wrapper1.eq("store_id", storeId);
                wrapper2.eq("store_id", storeId);
                wrapper3.eq("store_id", storeId);
                wrapper4.eq("store_id", storeId);
                wrapper5.eq("store_id", storeId);
                wrapper6.eq("store_id", storeId);
                wrapper7.eq("store_id", storeId);
                wrapper8.eq("store_id", storeId);
                wrapper9.eq("store_id", storeId);
                wrapper10.eq("store_id", storeId);
                wrapper11.eq("store_id", storeId);
                wrapper12.eq("store_id", storeId);
                wrapper13.eq("store_id", storeId);
                wrapper14.eq("store_id", storeId);
                wrapper15.eq("store_id", storeId);
                wrapper16.eq("store_id", storeId);
                wrapper17.eq("store_id", storeId);

            }

            if (!regionId.equals("")){
                wrapper.eq("region_id", regionId);
                wrapper1.eq("region_id", regionId);
                wrapper2.eq("region_id", regionId);
                wrapper3.eq("region_id", regionId);
                wrapper4.eq("region_id", regionId);
                wrapper5.eq("region_id", regionId);
                wrapper6.eq("region_id", regionId);
                wrapper7.eq("region_id", regionId);
                wrapper8.eq("region_id", regionId);
                wrapper9.eq("region_id", regionId);
                wrapper10.eq("region_id", regionId);
                wrapper11.eq("region_id", regionId);
                wrapper12.eq("region_id", regionId);
                wrapper13.eq("region_id", regionId);
                wrapper14.eq("region_id", regionId);
                wrapper15.eq("region_id", regionId);
                wrapper16.eq("region_id", regionId);
                wrapper17.eq("region_id", regionId);

            }

            Map<String, Object> dailyStatistics = new HashMap<>();
            dailyStatistics.put("daily", day);
            Integer appointmentTotal = appointmentMapper.selectCount(wrapper.likeRight("create_at",day));
            dailyStatistics.put("appointmentTotal", appointmentTotal);
            Integer billingTotal = appointmentMapper.selectCount(wrapper1.eq("state", 2).likeRight("create_at", day));
            dailyStatistics.put("billingTotal", billingTotal);
            if (billingTotal == 0){
                dailyStatistics.put("billingRate", "0.0%");
            }else {
                float billingRate = billingTotal/appointmentTotal;
                dailyStatistics.put("billingRate", Float.toString(billingRate * 100) + "%");
            }
            float appointmentPlumpness = appointmentMapper.selectCount(wrapper3.ne("type", 3).likeRight("create_at",day)).floatValue()/staffService.queryBookableNumber(storeId, day).floatValue();
            dailyStatistics.put("appointmentPlumpness", Float.toString(appointmentPlumpness*100)+"%");
            dailyStatistics.put("arrangementStore", appointmentMapper.selectCount(wrapper4.eq("type", 2).likeRight("create_at",day)));
            dailyStatistics.put("appointedBeautician", appointmentMapper.selectCount(wrapper5.eq("type", 1).likeRight("create_at",day)));
            dailyStatistics.put("provisionalDisposition", appointmentMapper.selectCount(wrapper6.eq("type", 3).likeRight("create_at",day)));
            dailyStatistics.put("memberAppointment", appointmentMapper.selectCount(wrapper7.eq("user_type", 1).likeRight("create_at",day)));
            dailyStatistics.put("individualBooking", appointmentMapper.selectCount(wrapper8.eq("user_type", 0).likeRight("create_at",day)));
            dailyStatistics.put("appBooking", appointmentMapper.selectCount(wrapper9.eq("source", 2).likeRight("create_at", day)));
            dailyStatistics.put("telephoneReservation", appointmentMapper.selectCount(wrapper10.eq("source", 3).likeRight("create_at",day)));
            dailyStatistics.put("storeBooking", appointmentMapper.selectCount(wrapper11.eq("source", 1).likeRight("create_at",day)));
            dailyStatistics.put("groupPurchaseBooking", appointmentMapper.selectCount(wrapper12.eq("source", 4).likeRight("create_at",day)));
            dailyStatistics.put("singleBooking", appointmentMapper.selectCount(wrapper13.eq("app_type", 0).likeRight("create_at",day)));
            dailyStatistics.put("consumptionAppointment", appointmentMapper.selectCount(wrapper14.eq("app_type", 1).likeRight("create_at",day)));
            dailyStatistics.put("morningAppointment", appointmentMapper.selectCount(wrapper15.le("create_at", day +" " + "12:00:00").likeRight("create_at",day)));
            dailyStatistics.put("afternoonAppointment", appointmentMapper.selectCount(wrapper16.gt("create_at", day +" " + "12:00:00").le("create_at", day +" " + "18:00:00").likeRight("create_at",day)));
            dailyStatistics.put("eveningAppointment", appointmentMapper.selectCount(wrapper17.gt("create_at", day +" " + "18:00:00").likeRight("create_at",day)));
            dailyStatisticsList.add(dailyStatistics);
        }

        Map<String, Object> msg = new HashMap<String, Object>();
        msg.put("massage", "查询成功");
        msg.put("code", 200);
        Map<String, Object> data = new HashMap<String, Object>();
        msg.put("data", data);
        data.put("rows", dailyStatisticsList);
        data.put("total", dailyStatisticsList.size());

        return msg;
    }
}
